local skynet = require "skynet"

local RaceRoom = {}

RaceRoom.Stage = {
    None = 0,
    Prepare = 1,
    Racing = 2,
    End = 3,
}

local gReadyTimeout = 15 * 100
local gRaceTimeout = 60 * 3 * 100

function RaceRoom:new(room_id)
    local o = {
        room_id = room_id or 0,
        players = {},
        openids = {},
        stage_ = RaceRoom.Stage.None,
        timer_ = nil,
        userData_ = nil,
        onRaceTimeout = nil,
        onReadyTimeout = nil,
        onRaceEnd = nil,
    }
    setmetatable(o,self)
    self.__index = self
    return o
end

function RaceRoom:getRoomId()
    return self.room_id
end

function RaceRoom:getStage()
    return self.stage_
end

function RaceRoom:setUserData(d)
    self.userData_ = d
end

function RaceRoom:getUserData()
    return self.userData_
end

function RaceRoom:isRacing()
    return self.stage_ == RaceRoom.Stage.Racing
end

function RaceRoom:addPlayer(player)
    if self.openids[player:getOpenID()] then
        return false
    end
    self.openids[player:getOpenID()] = player
    table.insert(self.players,player)
    return true
end

function RaceRoom:getPlayerByIndex(index)
    if index >= 1 and index < #self.players then
        return self.players[index]
    end
    return nil
end

function RaceRoom:getPlayerByOpenID(openid)
    local player = self.openids[openid]
    if player then
        return player
    end
    return nil
end

function RaceRoom:foreachPlayers(func)
    for _,player in ipairs(self.players) do
        func(player)
    end
end

function RaceRoom:_onReadyTimeoutProc()

    self.stage_ = RaceRoom.Stage.End

    self.timer_ = nil

    if self.onReadyTimeout then
        self.onReadyTimeout(self)
    end

end

function RaceRoom:onPrepare()

    if self:getStage() ~= RaceRoom.Stage.None then
        return false
    end

    self.stage_ = RaceRoom.Stage.Prepare

    self.timer_ = skynet.timeout(gReadyTimeout,function()
        self:_onReadyTimeoutProc()
    end)

    return true

end

function RaceRoom:_onRaceTimeoutProc()

    self.stage_ = RaceRoom.Stage.End

    self.timer_ = nil

    if self.onRaceTimeout then
        self.onRaceTimeout(self)
    end

end

function RaceRoom:_stopTimer()
    if self.timer_ then
        skynet.killthread(self.timer_)
        self.timer_ = nil
    end
end

function RaceRoom:checkReady()

    if self:getStage() ~= RaceRoom.Stage.Prepare then
        return false
    end

    local ok = true
    for _,player in ipairs(self.players) do
        if not player:isReady() then
            ok = false
            break
        end
    end

    if not ok then
        return true
    end

    self:_stopTimer()

    self.stage_ = RaceRoom.Stage.Racing

    self.timer_ = skynet.timeout(gRaceTimeout,function()

        self:_onRaceTimeoutProc()

    end)

    return true

end

function RaceRoom:onEnd()

    if self:getStage() ~= RaceRoom.Stage.Racing then
        return false
    end

    self:_stopTimer()

    self.stage_ = RaceRoom.Stage.End

    if self.onRaceEnd then
        self.onRaceEnd(self)
    end

    return true

end

return RaceRoom